package cplex;

/* --------------------------------------------------------------------------
 * File: CutStock.java
 * Version 12.5  
 * --------------------------------------------------------------------------
 * Licensed Materials - Property of IBM
 * 5725-A06 5725-A29 5724-Y48 5724-Y49 5724-Y54 5724-Y55 5655-Y21
 * Copyright IBM Corporation 2001, 2013. All Rights Reserved.
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with
 * IBM Corp.
 * --------------------------------------------------------------------------
 */

import identical_scheduling_algorithm.Cofiguration;
import identical_scheduling_algorithm.RoundJobs;
import ilog.concert.*;

import java.util.*;

import ilog.cplex.*;

import java.io.*;

import de.cau.apo.problems.identicalscheduling.ISInstance;
import de.cau.apo.problems.identicalscheduling.Job;

class CutStock {
   static double RC_EPS = 1.0e-6;
   
   // Data of the problem
   
   static double   _rollWidth;
   static double[] _size;
   static double[] _amount;
   
   public static void main (String [] args){
	   lpSolver();
   }
   
   static void readData(double delta, double makeSpan, Job [] jobs) {
     
      
      //_rollWidth = reader.readDouble();-- = Bingroeße
	   _rollWidth =1;
	
      //Anzahl der Jobs 
      _amount    = null;
      
      
      // gerundete Werte p_j
      _size      =  new double[_amount.length];
      for(int i =0; i< _size.length; i++){
    	  _size[i]= delta* Math.pow((delta + 1), i);
    	  System.out.println(_size[i]);
      }
   }
   
   static void report1(IloCplex cutSolver, IloNumVarArray Cut, IloRange[] Fill) 
                         throws IloException {
      System.out.println();
      System.out.println("Using " + cutSolver.getObjValue() + " rolls");
    
      System.out.println();
      for (int j = 0; j < Cut.getSize(); j++) {
         System.out.println("  Cut" + j + " = " +
                            cutSolver.getValue(Cut.getElement(j)));
      }
      System.out.println();
      
      for (int i = 0; i < Fill.length; i++) 
         System.out.println("  Fill" + i + " = " + cutSolver.getDual(Fill[i]));
      System.out.println();
   }
   
   static void report2(IloCplex patSolver, IloNumVar[] Use) 
                         throws IloException {
      System.out.println();
      System.out.println("Reduced cost is " + patSolver.getObjValue());
      
      System.out.println();
      if (patSolver.getObjValue() <= -RC_EPS) {
         for (int i = 0; i < Use.length; i++) 
            System.out.println("  Use" + i + " = "
                               + patSolver.getValue(Use[i]));
         System.out.println();
      }
   }
   

   static class IloNumVarArray {
      int _num           = 0;
      IloNumVar[] _array = new IloNumVar[32];

      void add(IloNumVar ivar) {
         if ( _num >= _array.length ) {
            IloNumVar[] array = new IloNumVar[2 * _array.length];
            System.arraycopy(_array, 0, array, 0, _num);
            _array = array;
         }
         _array[_num++] = ivar;
      }

      IloNumVar getElement(int i) { return _array[i]; }
      int       getSize()         { return _num; }
   }

   public static Cofiguration lpSolver() {
	   
	   // Matrix zum Speichern der Config.
	   ArrayList<ArrayList<Integer>> matrix = new ArrayList<ArrayList<Integer>>();
	   ArrayList<Double> solution = new ArrayList<Double>();
	   
	   
	   ISInstance instanz = new ISInstance();
		try {
			if(instanz.parseInstance("INSTANCES/NU_2_0010_05_1.txt"))
			{
				double delta = 0.05;
				double makeSpan = 2000;
			readData(delta, makeSpan, instanz.jobs);
			
			
         /// CUTTING-OPTIMIZATION PROBLEM ///
       
         IloCplex cutSolver = new IloCplex();
       
         IloObjective RollsUsed = cutSolver.addMinimize();
         IloRange[]   Fill = new IloRange[_amount.length];
         for (int f = 0; f < _amount.length; f++ ) {
            Fill[f] = cutSolver.addRange(_amount[f], Double.MAX_VALUE);
            
         }
       
         IloNumVarArray Cut = new IloNumVarArray();
       
         int nWdth = _size.length;
         System.out.println("Startmatrix: ");
         for (int j = 0; j < nWdth; j++){
            Cut.add(cutSolver.numVar(cutSolver.column(RollsUsed, 1.0).and(
                                     cutSolver.column(Fill[j],
                                                      (int)(_rollWidth/_size[j]))),
                                     0.0, Double.MAX_VALUE));
            
            ArrayList<Integer> column = new ArrayList<Integer>();
            for(int i= 0; i< nWdth; i++){
            	if(i == j)
            		column.add((int)(_rollWidth/_size[j]));
            	else
            		column.add(0);            	
            }
            matrix.add(column);
            
            
            for(int value: column)
            	System.out.print(value);
            System.out.println();
         }       
                    System.out.println();

         cutSolver.setParam(IloCplex.IntParam.RootAlg, IloCplex.Algorithm.Primal);
       
         /// PATTERN-GENERATION PROBLEM ///
       
         IloCplex patSolver = new IloCplex();
       
         IloObjective ReducedCost = patSolver.addMinimize();
         IloNumVar[] Use = patSolver.numVarArray(nWdth, 
                                                 0., Double.MAX_VALUE, 
                                                 IloNumVarType.Int);
         patSolver.addRange(-Double.MAX_VALUE, 
                            patSolver.scalProd(_size, Use),
                            _rollWidth);
       
         /// COLUMN-GENERATION PROCEDURE ///
       
         double[] newPatt = new double[nWdth];
       
         /// COLUMN-GENERATION PROCEDURE ///
       
         for (;;) {
            /// OPTIMIZE OVER CURRENT PATTERNS ///
          System.out.println(_size[1]);
          System.out.println(_amount[1]);

            cutSolver.solve();
            report1(cutSolver, Cut, Fill);
          
            /// FIND AND ADD A NEW PATTERN ///
          
            double[] price = cutSolver.getDuals(Fill);
            ReducedCost.setExpr(patSolver.diff(1.,
                                               patSolver.scalProd(Use, price)));
          
            patSolver.solve();
            report2 (patSolver, Use);
          
            if ( patSolver.getObjValue() > -RC_EPS )
               break;
          
            
            newPatt = patSolver.getValues(Use);
            
            
            // Sichern der Config.
            ArrayList<Integer> spalte = new ArrayList<Integer>();
            for(int i =0; i <newPatt.length; i++)
            	spalte.add((int)newPatt[i]);
            matrix.add(spalte);
           
            IloColumn column = cutSolver.column(RollsUsed, 1.);
            for ( int p = 0; p < newPatt.length; p++ )
               column = column.and(cutSolver.column(Fill[p], newPatt[p]));
            
            Cut.add( cutSolver.numVar(column, 0., Double.MAX_VALUE) );
         }
         
         for(int i= 0;i < Cut.getSize();i++)
        	 solution.add(cutSolver.getValue(Cut.getElement(i)));
         
        
         
       
         System.out.println("Solution status: " + cutSolver.getStatus());       
         cutSolver.end();
         patSolver.end();
         return new Cofiguration(matrix,solution);
      }
		}
      catch ( IloException exc ) {
         System.err.println("Concert exception '" + exc + "' caught");
      }
	  catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
   }
}


